﻿using System.Collections.Specialized;
using System.Globalization;

namespace ProxyServer.ProxyImpl
{
    public class HttpRequestContext
    {
        protected HttpRequestContext(string httpQuery)
        {
            HttpQuery = httpQuery;
        }

        public string this[string key]
        {
            get
            {
                return HeaderFields != null && HeaderFields.ContainsKey(key) ? HeaderFields[key] : string.Empty;
            }
        }

        public StringDictionary HeaderFields { get; set; }

        public string HttpVersion { get; set; }

        public string HttpRequestType { get; set; }

        public string RequestedPath { get; set; }

        public string HttpPost { get; set; }

        public string HttpQuery { get; set; }

        public string Host { get; set; }

        public int Port { get; set; }


        public static HttpRequestContext ParseQuery(string query)
        {
            var context = new HttpRequestContext(query);

            var retdict = new StringDictionary();

            string[] lines = query.Replace("\r\n", "\n").Split('\n');
            int cnt, ret;

            if (lines.Length > 0)
            {
                ret = lines[0].IndexOf(' ');
                if (ret > 0)
                {
                    context.HttpRequestType = lines[0].Substring(0, ret);
                    lines[0] = lines[0].Substring(ret).Trim();
                }

                ret = lines[0].LastIndexOf(' ');
                if (ret > 0)
                {
                    context.HttpVersion = lines[0].Substring(ret).Trim();
                    context.RequestedPath = lines[0].Substring(0, ret);
                }
                else
                {
                    context.RequestedPath = lines[0];
                }

                if (context.RequestedPath.Length >= 7 && context.RequestedPath.Substring(0, 7).ToLower(CultureInfo.InvariantCulture).Equals("http://"))
                {
                    ret = context.RequestedPath.IndexOf('/', 7);
                    context.RequestedPath = ret == -1 ? "/" : context.RequestedPath.Substring(ret);
                }
            }

            for (cnt = 1; cnt < lines.Length; cnt++)
            {
                ret = lines[cnt].IndexOf(":");
                if (ret > 0 && ret < lines[cnt].Length - 1)
                {
                    retdict.Add(lines[cnt].Substring(0, ret), lines[cnt].Substring(ret + 1).Trim());
                }
            }

            context.HeaderFields = retdict;

            context.ExtractHost();

            return context;
        }

        public string RebuildQuery()
        {
            string ret = HttpRequestType + " " + RequestedPath + " " + HttpVersion + "\r\n";
            if (HeaderFields != null)
            {
                foreach (string sc in HeaderFields.Keys)
                {
                    if (sc.Length < 6 || !sc.Substring(0, 6).Equals("proxy-"))
                        ret += CultureInfo.CurrentCulture.TextInfo.ToTitleCase(sc) + ": " + HeaderFields[sc] + "\r\n";
                }

                ret += "\r\n";

                if (!string.IsNullOrEmpty(HttpPost))
                    ret += HttpPost;
            }
            return ret;
        }

        protected void ExtractHost()
        {
            if (HttpRequestType.ToUpper().Equals("CONNECT"))
            {
                //HTTPS
                int ret = RequestedPath.IndexOf(":");
                if (ret >= 0)
                {
                    Host = RequestedPath.Substring(0, ret);
                    Port = RequestedPath.Length > ret + 1 ? int.Parse(RequestedPath.Substring(ret + 1)) : 443;
                }
                else
                {
                    Host = RequestedPath;
                    Port = 443;
                }
            }
            else
            {
                //Normal HTTP
                int ret = (HeaderFields["Host"]).IndexOf(":");
                if (ret > 0)
                {
                    Host = (HeaderFields["Host"]).Substring(0, ret);
                    Port = int.Parse((HeaderFields["Host"]).Substring(ret + 1));
                }
                else
                {
                    Host = HeaderFields["Host"];
                    Port = 80;
                }

                if (HttpRequestType.ToUpper().Equals("POST"))
                {
                    int index = HttpQuery.IndexOf("\r\n\r\n");
                    HttpPost = HttpQuery.Substring(index + 4);
                }
            }
        }
    }
}